
package com.ru.application.creditscore.dao.support;

import static com.google.common.collect.Lists.newArrayList;

import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.ru.application.creditscore.dao.support.JpaUtil;
import com.ru.application.creditscore.dao.support.PropertySelector;

/**
 * Helper to create a predicate out of {@link PropertySelector}s.
 */
public class ByPropertySelectorUtil {
    @SuppressWarnings("unchecked")
    public static <E> Predicate byPropertySelectors(Root<E> root, CriteriaBuilder builder, final List<PropertySelector<?, ?>> selectors) {
        List<Predicate> predicates = newArrayList();

        for (PropertySelector<?, ?> selector : selectors) {
            if (selector.isBoolean()) {
                byBooleanSelector(root, builder, predicates, (PropertySelector<E, Boolean>) selector);
            } else {
                byObjectSelector(root, builder, predicates, (PropertySelector<E, ?>) selector);
            }
        }
        return JpaUtil.andPredicate(builder, predicates);
    }

    private static <E> void byBooleanSelector(Root<E> root, CriteriaBuilder builder, List<Predicate> predicates, PropertySelector<E, Boolean> selector) {
        if (selector.isNotEmpty()) {
            List<Predicate> selectorPredicates = newArrayList();

            for (Boolean selection : selector.getSelected()) {
                Path<Boolean> path = root.get(selector.getField());
                if (selection == null) {
                    selectorPredicates.add(builder.isNull(path));
                } else {
                    selectorPredicates.add(selection ? builder.isTrue(path) : builder.isFalse(path));
                }
            }
            predicates.add(JpaUtil.orPredicate(builder, selectorPredicates));
        }
    }

    private static <E> void byObjectSelector(Root<E> root, CriteriaBuilder builder, List<Predicate> predicates, PropertySelector<E, ?> selector) {
        if (selector.isNotEmpty()) {
            List<Predicate> selectorPredicates = newArrayList();

            for (Object selection : selector.getSelected()) {
                Path<?> path = root.get(selector.getField());
                selectorPredicates.add(selection == null ? builder.isNull(path) : builder.equal(path, selection));
            }
            predicates.add(JpaUtil.orPredicate(builder, selectorPredicates));
        }
    }
}
